package org.lc.stk.service.user.impl;

import jakarta.persistence.criteria.Join;
import jakarta.persistence.criteria.JoinType;
import org.lc.stk.dao.RoleRepository;
import org.lc.stk.dao.UserRepository;
import org.lc.stk.model.baseInfo.Department;
import org.lc.stk.model.user.Role;
import org.lc.stk.model.user.Student;
import org.lc.stk.model.user.Teacher;
import org.lc.stk.model.user.User;
import org.lc.stk.model.user.UserRole;
import org.lc.stk.service.exception.BusinessException;
import org.lc.stk.service.user.UserService;
import org.lc.stk.web.dto.user.BulkOperationRequest;
import org.lc.stk.web.dto.user.UserAdminCreateRequest;
import org.lc.stk.web.dto.user.UserQuery;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.HashSet;
import java.util.Set;

@Service
@Transactional
public class UserServiceImpl implements UserService {

    private final UserRepository userRepository;
    private final RoleRepository roleRepository;
    private final PasswordEncoder passwordEncoder;

    public UserServiceImpl(UserRepository userRepository, 
                         RoleRepository roleRepository,
                         PasswordEncoder passwordEncoder) {
        this.userRepository = userRepository;
        this.roleRepository = roleRepository;
        this.passwordEncoder = passwordEncoder;
    }

    @Override
    public User findByUsername(String username) {
        return userRepository.findByUsername(username)
                .orElse(null);
    }

    @Override
    public boolean existsByUsername(String username) {
        return userRepository.existsByUsername(username);
    }

    @Override
    public User createUser(UserAdminCreateRequest request) {
        if (existsByUsername(request.getUsername())) {
            throw new BusinessException("用户名已存在");
        }

        User user;
        if ("student".equals(request.getUserType())) {
            user = new Student();
        } else if ("teacher".equals(request.getUserType())) {
            user = new Teacher();
        } else {
            throw new BusinessException("无效的用户类型");
        }

        user.setUsername(request.getUsername());
        user.setPassword(passwordEncoder.encode(request.getPassword()));
        user.setName(request.getRealName());
        user.setEmail(request.getEmail());
        user.setState(User.UserState.ENABLED);
        user.setDeleted(false);

        Department dept = new Department();
        dept.setId(request.getDepartmentId());
        user.setDepartment(dept);

        if (request.getRoleIds() != null && !request.getRoleIds().isEmpty()) {
            Set<UserRole> userRoles = new HashSet<>();
            for (Integer roleId : request.getRoleIds()) {
                Role role = roleRepository.findById(roleId)
                        .orElseThrow(() -> new BusinessException("角色不存在: " + roleId));
                UserRole userRole = new UserRole();
                userRole.setUser(user);
                userRole.setRole(role);
                userRoles.add(userRole);
            }
            user.setRoles(userRoles);
        }

        return userRepository.save(user);
    }

    @Override
    public User updateUser(Integer id, UserAdminCreateRequest request) {
        User user = userRepository.findById(id)
                .orElseThrow(() -> new BusinessException("用户不存在"));

        if (!user.getUsername().equals(request.getUsername()) 
            && existsByUsername(request.getUsername())) {
            throw new BusinessException("用户名已存在");
        }

        user.setUsername(request.getUsername());
        if (StringUtils.hasText(request.getPassword())) {
            user.setPassword(passwordEncoder.encode(request.getPassword()));
        }
        user.setName(request.getRealName());
        user.setEmail(request.getEmail());

        Department dept = new Department();
        dept.setId(request.getDepartmentId());
        user.setDepartment(dept);

        if (request.getRoleIds() != null) {
            Set<UserRole> userRoles = new HashSet<>();
            for (Integer roleId : request.getRoleIds()) {
                Role role = roleRepository.findById(roleId)
                        .orElseThrow(() -> new BusinessException("角色不存在: " + roleId));
                UserRole userRole = new UserRole();
                userRole.setUser(user);
                userRole.setRole(role);
                userRoles.add(userRole);
            }
            user.setRoles(userRoles);
        }

        return userRepository.save(user);
    }

    @Override
    public void deleteUser(Integer id) {
        User user = userRepository.findById(id)
                .orElseThrow(() -> new BusinessException("用户不存在"));
        user.setDeleted(true);
        userRepository.save(user);
    }

    @Override
    public User getUser(Integer id) {
        return userRepository.findById(id)
                .orElseThrow(() -> new BusinessException("用户不存在"));
    }

    @Override
    public Page<User> searchUsers(UserQuery query, Pageable pageable) {
        Specification<User> spec = (root, criteriaQuery, cb) -> {
            var predicates = new HashSet<>();

            if (StringUtils.hasText(query.getUsername())) {
                predicates.add(cb.like(root.get("username"), "%" + query.getUsername() + "%"));
            }
            
            if (StringUtils.hasText(query.getRealName())) {
                predicates.add(cb.like(root.get("name"), "%" + query.getRealName() + "%"));
            }

            if (query.getDepartmentId() != null) {
                predicates.add(cb.equal(root.get("department").get("id"), query.getDepartmentId()));
            }

            if (query.getRoleId() != null) {
                Join<User, UserRole> userRoleJoin = root.join("roles", JoinType.LEFT);
                predicates.add(cb.equal(userRoleJoin.get("role").get("id"), query.getRoleId()));
            }

            if (StringUtils.hasText(query.getUserType())) {
                if ("student".equals(query.getUserType())) {
                    predicates.add(cb.equal(root.type(), Student.class));
                } else if ("teacher".equals(query.getUserType())) {
                    predicates.add(cb.equal(root.type(), Teacher.class));
                }
            }

            predicates.add(cb.equal(root.get("deleted"), false));
            
            return cb.and(predicates.toArray(new jakarta.persistence.criteria.Predicate[0]));
        };

        return userRepository.findAll(spec, pageable);
    }

    @Override
    public void bulkOperation(BulkOperationRequest request) {
        request.validate();
        switch (request.getOperationType()) {
            case ASSIGN_ROLES:
                assignRoles(request.getUserIds(), request.getRoleIds());
                break;
            case DELETE:
                deleteUsers(request.getUserIds());
                break;
            default:
                throw new BusinessException("不支持的操作类型");
        }
    }

    @Override
    public void assignRoles(Set<Integer> userIds, Set<Integer> roleIds) {
        Set<Role> roles = new HashSet<>();
        for (Integer roleId : roleIds) {
            roles.add(roleRepository.findById(roleId)
                    .orElseThrow(() -> new BusinessException("角色不存在: " + roleId)));
        }

        for (Integer userId : userIds) {
            User user = userRepository.findById(userId)
                    .orElseThrow(() -> new BusinessException("用户不存在: " + userId));
            
            Set<UserRole> userRoles = new HashSet<>();
            for (Role role : roles) {
                UserRole userRole = new UserRole();
                userRole.setUser(user);
                userRole.setRole(role);
                userRoles.add(userRole);
            }
            user.setRoles(userRoles);
            userRepository.save(user);
        }
    }

    @Override
    public void deleteUsers(Set<Integer> userIds) {
        for (Integer userId : userIds) {
            User user = userRepository.findById(userId)
                    .orElseThrow(() -> new BusinessException("用户不存在: " + userId));
            user.setDeleted(true);
            userRepository.save(user);
        }
    }
}
